#-*-coding:utf-8-*-
'''
Created on 04.Şub.2010

@authors:	Aşkın Yollu <askin@askin.ws>
            Erdem Artan <baDibere@gmail.com>

'''

from xml.dom.minidom import parse, Document, parseString
import bz2, urllib, os, os.path
from tempfile import gettempdir
import xml.etree.cElementTree as etree

# parse pisi-index and, return packages with versions
def parsePisiIndex(pisiIndex):
    packages = {}

    datasource = open(pisiIndex)
    packagetree = etree.fromstring(datasource.read())

    package_nodes = packagetree.findall("Package")
    for pkg_node in package_nodes:
        history_node = pkg_node.find("History")
        update_node = history_node.getchildren()[0]
        try:
            name = pkg_node.findtext("Name")
            version = update_node.findtext("Version")
            release = update_node.get("release")
            package_size = pkg_node.findtext("PackageSize")
            package_hash = pkg_node.findtext("PackageHash")
            package_url = pkg_node.findtext("PackageURI")

            packages[name] = (version, release, package_size, package_hash, package_url)
        except:
            pass

    return packages

def parseInstalledPackageXML(installedXml):
    packages = []

    datasource = open(installedXml)
    installed_tree = etree.fromstring(datasource.read())

    repo_nodes = installed_tree.findall("Repo")

    ''' structure example
        {
            "contrib": {"pkg2" : ("pkg1, "1.0", "2"), "pkg2" : ("pkg2", "3.5", "4", "http://paketler.pardus.org.tr/pardus-2009/")},
            "pardus-2009" : {"pkg2" : ("pkg1, "1.0", "2"), "pkg2" : ("pkg2", "3.5", "4", "http://paketler.pardus.org.tr/contrib-2009/")}
        }
    '''
    installed_package_with_repo = {}
    for repo_node in repo_nodes:
        repo = repo_node.get("repo")
        repo_uri = repo_node.get("repo_uri")
        for pkg in repo_node.findall("package"):
            name = pkg.findtext("name")
            version = pkg.findtext("version")
            release = pkg.findtext("release")

            try:
                installed_package_with_repo[repo][name] = (name, version, release, repo_uri)
            except:
                installed_package_with_repo[repo] = {}
                installed_package_with_repo[repo][name] = (name, version, release, repo_uri)

    return installed_package_with_repo

def getUpdatedPackages(oldDB, freshDB):
    updates = []
    for repo in oldDB:
        for pkg in oldDB[repo]:
            try:
                old_name, old_version, old_release, repo_url = oldDB[repo][pkg]
                fresh_name = pkg
                print fresh_name
                fresh_version = freshDB[repo][pkg][0]
                print fresh_version
                fresh_release = freshDB[repo][pkg][1]
                print fresh_release
                version, release, package_size, package_hash, package_url = freshDB[repo][pkg]

                if(fresh_version > old_version):
                    updates.append({"name" : pkg,
                                    "version" : version,
                                    "release" : release,
                                    "size" : package_size,
                                    "hash" : package_hash,
                                    "url" : "%s%s" % (repo_url, package_url)})
                elif(fresh_release > old_release):
                    updates.append({"name" : pkg,
                                    "version" : version,
                                    "release" : release,
                                    "size" : package_size,
                                    "hash" : package_hash,
                                    "url" : "%s%s" % (repo_url, package_url)})
                else:
                    pass
            except:
                pass

    return updates

'''
Güncel PiSi indexi ile, kurulu paketleri karşılaştırarak
güncellenecek paketleri bulup, isim, indirme adresi gibi
bigileri updates.pdx dosyasına yazar

Bu fonksiyonun çalışabilmesi için daha önce güncellenecek
sistemden kurulu paketlerin listesi alınmalı, ardından
internet olan bir makinede pisi index elde edilip karşılaştırma
yapılmalı.

freshRepos {"contrib" : "contrib-pisi-index.xml"}
'''
def writeUpdatedPackages(installedPackageList, fileName):
    freshDB = {}
    freshRepos = {}
    freshRepoFiles = {}
    # kurulu paketler
    currentDB = parseInstalledPackageXML(installedPackageList)

    # depo adreslerinin alınması
    for repo in currentDB:
        freshRepos[repo] = "%s/%s" % (currentDB[repo][currentDB[repo].keys()[0]][3], "pisi-index.xml.bz2")

    # depoların indirilmesi
    for repo in freshRepos:
        urllib.urlretrieve(freshRepos[repo], os.path.join(gettempdir(), "%s-pisi-index.xml.bz2" % repo))
        content = bz2.BZ2File(os.path.join(gettempdir(), "%s-pisi-index.xml.bz2" % repo)).read()
        fl = open(os.path.join(gettempdir(), "%s-pisi-index.xml" % repo), "w")
        fl.write(content)
        fl.close()
        freshRepoFiles[repo] = os.path.join(gettempdir(), "%s-pisi-index.xml" % repo)

    # pisi indexin parse edilmesi
    for repo in freshRepos:
        freshDB[repo] = parsePisiIndex(freshRepoFiles[repo])
    # kurulu paketlerle pisi indexin karşılaştırılması
    updates = getUpdatedPackages(currentDB, freshDB)
    writePDX(updates, freshRepos, fileName)

def writePDX(updates, repos, fileName):
    # pdx'in oluşturulması
    doc = Document()
    # root element
    root = doc.createElement("PiSiDown")
    doc.appendChild(root)

    if len(repos) > 0:
        _repos = doc.createElement("Repos")
        root.appendChild(_repos)

    for r in repos:
        _repo = doc.createElement("Repo")
        _repo.setAttribute("name", r)
        _repos.appendChild(_repo)
        text = doc.createTextNode(repos[r])
        _repo.appendChild(text)

    for pkg in updates:
        package = doc.createElement("Package")
        root.appendChild(package)

        name = doc.createElement("Name")
        package.appendChild(name)
        text = doc.createTextNode(pkg["name"])
        name.appendChild(text)

        url = doc.createElement("URI")
        package.appendChild(url)
        text = doc.createTextNode(pkg["url"])
        url.appendChild(text)

        pkghash = doc.createElement("Sha1Sum")
        package.appendChild(pkghash)
        text = doc.createTextNode(pkg["hash"])
        pkghash.appendChild(text)

    file = open(fileName, "w")
    doc.writexml(file)

'''
Güncellenecek paketlerin listesinin tutulduğu
pdx dosyasını okuyup gerekli bilgileri döndürür
formatı:
[
 {"name" : "pkg1", "url" : "http://depo/paket1.pisi" : "hash" : "36b1ff2ff6a5e21dfd69fa9be76702e6486f83fb"},
 {"name" : "pkg2", "url" : "http://depo/paket2.pisi" : "hash" : "36b1ff2ff6a5e21dfd69fa9be76702e6486f83fb"}
]
'''
def readPDX(fileName):
    packages = []
    resource = open(fileName)
    pdx_tree = etree.fromstring(resource.read())
    pkg_nodes = pdx_tree.findall("Package")
    for pkg_node in pkg_nodes:
        name = pkg_node.findtext("Name")
        url = pkg_node.findtext("URI")
        pkg_hash = pkg_node.findtext("Sha1Sum")

        packages.append({"name": name, "url" : url, "hash" : pkg_hash})

    return packages

def getDownloadListHTML(updates, file_name):
    web_page = '''<head><title>PiSi Down Download List</title></head>
<html>
    <body>
        <ol>\n'''

    for pkg in updates:
        web_page += '            <li><a href="%s" target="_blank">%s - %s</a></li>\n' % (pkg[5], pkg[0], pkg[1])

    web_page += "        </ol>\n    <body>\n</html>\n"

    page_file = open(file_name, "w")
    page_file.write(web_page)

#Acaba Pardus mu kullanıyor?
def isPardus():
    try:
        import pisi
        return True
    except:
        return False

'''
internet bağlantısı varmı yokmu kontrol et
'''
def checkInternet():
    ip = "google.com"
    ping = os.popen("ping -q -c2 " + ip)
    lines = ping.readlines()
    if(lines.find("100% packet loss") > -1):
        return False
    else:
        return True

'''
Kurulu paketlerin listesinden, repo adlarını ve
repo adreslerini alır.
Bu Options sınıfı içerisinde kullanılacak

Çıktı:
[("repo", "http://repo.com/repo")]
'''
def getReposFromInstalledXml(xmlname):
    repos = []

    datasource = open(xmlname)
    installed_tree = etree.fromstring(datasource.read())

    repo_nodes = installed_tree.findall("Repo")

    for repo_node in repo_nodes:
        repo = repo_node.get("repo")
        repo_uri = repo_node.get("repo_uri")

        repos.append((repo, repo_uri))

    return repos

'''
PDX Dosyasından, repo adlarını ve repo adreslerini alır.
Bu Options sınıfı içerisinde kullanılacak

Çıktı:
[("repo", "http://repo.com/repo")]
'''
def getReposFromPDX(pdxname):
    repos = []

    datasource = open(pdxname)
    pdx_tree = etree.fromstring(datasource.read())

    repo_nodes = pdx_tree.findall("Repos/Repo")

    for repo_node in repo_nodes:
        name = repo_node.get("name")
        repo_uri = repo_node.findtext("./")

        repos.append((name, repo_uri))

    return repos
